package com.water.fish.widget

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.animation.AccelerateInterpolator
import android.view.animation.LinearInterpolator
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.water.fish.*
import com.water.fish.anim.MirrorRotationAnim
import com.water.fish.listener.PetAnimatorAdapter
import com.water.fish.utils.dp2px
import com.water.fish.widget.IMarineView.Companion.SPEED_MOVE_SECOND
import pl.droidsonroids.gif.GifImageView
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.random.Random

/**
 *  https://blog.csdn.net/Jiang_Rong_Tao/article/details/58635019
 *  鱼宠View.
 *  Created by zxn on 2021/6/1.
 **/
class PetView : ConstraintLayout, IWhaleView {

    companion object {

        private const val TAG = "PetView"

        /**
         *自动随机移动(MOVE_AUTO)
         */
        private const val MOVE_AUTO = 0

        /**
         * 手指触摸移动(MOVE_TOUCH)
         */
        private const val MOVE_TOUCH = 1

        /**
         * 寻找食物移动(MOVE_FEED)
         */
        private const val MOVE_FEED = 2

        /**
         * 停止移动
         */
        private const val MOVE_STOP = 3
    }

    constructor(context: Context) : this(context, null)

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        setWillNotDraw(false)
        LayoutInflater.from(context).inflate(R.layout.layout_pet_constraint, this, true)
    }

    val ivPetFish: GifImageView by lazy {
        findViewById(R.id.ivFish)
    }

    private val tvTips by lazy {
        findViewById<TextView>(R.id.tvTips)
    }

    private var mOnPetClickListener: OnClickListener? = null

    private var mPetFish: PetFish? = null

    /**
     * 组合动路径.
     * 0:p0->p1
     * 1:p1->p2
     * 2:p2->p3->p4->p5
     * 3:p5->p6
     * 4:p6->p7
     * 5:p7->p8
     * 6:p8->p9->p10->p11
     * 7:p11->p12
     */
    private val petPathList = mutableListOf<Path>()

    private val petAnimatorList = mutableListOf<Animator>()

    private val mPetAnimatorAdapter =
        PetAnimatorAdapter(this, petAnimatorList)

    /**
     * 休息的秒数
     */
    private var restDuration = 2

    /**
     * 转身持续时间.turnDuration
     */
    private val turnDuration = 60L

    private val mPathMeasure = PathMeasure()

    override var moveSpeed = 10L

    /**
     * 宠物移动范围
     */
    private val targetRect = Rect()

    private var petWidth = 0
    private var petHeight = 0

    override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
        super.onWindowFocusChanged(hasWindowFocus)
        Log.i(TAG, "onWindowFocusChanged: $hasWindowFocus")
        when (trailType) {
            1 -> {
                if (hasWindowFocus) {
                    petWidth = width
                    petHeight = height
                    if (moveType == MOVE_STOP) {
                        autoMove()
                    }
                }
            }
            else -> {
                if (moveType == MOVE_AUTO) {
                    mPetAnimatorAdapter.onWindowFocusChanged(hasWindowFocus)
                }
            }
        }
    }

    @SuppressLint("Recycle")
    override fun onInitMovement(rectF: RectF) {
        moveToStarting(rectF.right, rectF.bottom)
        when (trailType) {
            1 -> targetRect.let {
                it.left = rectF.left.toInt()
                it.right = rectF.right.toInt()
                it.top = rectF.top.toInt()
                it.bottom = rectF.bottom.toInt()
            }
            else -> initMovePath(rectF)
        }
    }

    /**
     * 自行移动
     */
    private fun autoMove() {
        moveType = MOVE_AUTO
        updateTarget()
        val targetX = targetPointF.x
        val nextDirection = nextDirection(targetX)
        if (currentDirection != nextDirection) {
            turnNext(nextDirection)
        } else {
            moveToTarget()
        }
    }

    /**
     * 初始化固定移动轨迹
     */
    private fun initMovePath(rectF: RectF) {
        petPathList.clear()
        for (index in 0 until 8) {
            val path = Path()
            rectF.run {
                when (index) {
                    //path0
                    0 -> {
                        path.moveTo(right, bottom)
                        path.lineTo(centerX(), centerY())
                    }
                    //path1
                    1 -> {
                        path.moveTo(centerX(), centerY())
                        path.lineTo(left, centerY())
                    }
                    //path2
                    2 -> {
                        path.moveTo(left, centerY())
                        path.lineTo(right, top)
                        path.lineTo(right, centerY())
                        path.lineTo(right, top)
                    }
                    //path3
                    3 -> {
                        path.moveTo(right, top)
                        path.lineTo(left, top)
                    }
                    //path4
                    4 -> {
                        path.moveTo(left, top)
                        path.lineTo(right, centerY())
                    }
                    //path5
                    5 -> {
                        path.moveTo(right, centerY())
                        path.lineTo(centerX(), centerY())
                    }
                    //path6
                    6 -> {
                        path.moveTo(centerX(), centerY())
                        path.lineTo(left, bottom)
                        path.lineTo(left, centerY())
                        path.lineTo(left, bottom)
                    }
                    //path7
                    7 -> {
                        path.moveTo(left, bottom)
                        path.lineTo(right, bottom)
                    }
                }
            }
            mPathMeasure.setPath(path, false)
            val moveDuration =
                (mPathMeasure.length.toLong() * SPEED_MOVE_SECOND / moveSpeed)
            val objectAnimator = ObjectAnimator.ofFloat(this, View.X, View.Y, path).apply {
                addListener(mPetAnimatorAdapter)
                interpolator = LinearInterpolator()
                duration = moveDuration
            }
            petAnimatorList.add(objectAnimator)
        }
    }

    override fun moveLeft() {
        when (trailType) {
            1 -> {
                //随机路线.
                ivPetFish.rotationY = 360F
            }
            else -> {
                //固定路线.
                //ivPetFish.rotationY = 360F
                //部分华为7.0手机,rotationY函数执行会导致view消失.
                ivPetFish.clearAnimation()
            }
        }
        mPetFish?.let {
            val resId = it.onMoveResId()
            if (resId != 0) {
                ivPetFish.setImageResource(resId)
            }
            onPetChangeListener?.invoke(it, this, PetAction.Move)
        }
    }

    private val mirrorRotationAnim = MirrorRotationAnim()

    override fun moveRight() {

        when (trailType) {
            1 -> {
                //随机路线.
                ivPetFish.rotationY = 180F
            }
            else -> {
                if (ivPetFish.animation == null) {
                    ivPetFish.startAnimation(mirrorRotationAnim)
                }
            }
        }
        mPetFish?.let {
            val resId = it.onMoveResId()
            if (resId != 0) {
                ivPetFish.setImageResource(resId)
            }
            onPetChangeListener?.invoke(it, this, PetAction.Move)
        }
    }

    override fun turnRight(nextAnimator: Animator) {
        turnRight()
        if (trailType == 0) {
            nextAnimator.startDelay = turnDuration
            nextAnimator.start()
        }
    }

    private fun turnRight() {
        mPetFish?.let {
            val resId = it.onTurnResId()
            if (resId != 0) {
                ivPetFish.setImageResource(resId)
            }
            onPetChangeListener?.invoke(it, this, PetAction.TURN)
        }
    }

    override fun turnLeft(nextAnimator: Animator) {
        turnLeft()
        nextAnimator.startDelay = turnDuration
        nextAnimator.start()
    }

    private fun turnLeft() {
        mPetFish?.let {
            val resId = it.onTurnResId()
            if (resId != 0) {
                ivPetFish.setImageResource(resId)
            }
            onPetChangeListener?.invoke(it, this, PetAction.TURN)
        }
    }

    override fun pause(animation: Animator) {
        animation.pause()
    }

    override fun resume(animation: Animator) {
        animation.resume()
    }

    override fun travel() {
        mPetAnimatorAdapter.end()
        visibility = View.GONE
    }

    override fun rest(position: Int, nextAnimator: Animator) {
        nextAnimator.startDelay = restDuration * SPEED_MOVE_SECOND
        nextAnimator.start()
        mPetFish?.let {
            onPetChangeListener?.invoke(it, this, PetAction.REST)
        }
    }

    override fun start(nextAnimator: Animator) {
        if (!nextAnimator.isStarted && !nextAnimator.isRunning) {
            nextAnimator.startDelay = turnDuration
            nextAnimator.start()
        }
    }

    override fun onChanged(entity: FishEntity) {
        mPetFish = entity as PetFish
        mPetFish?.let {
            if (it.moveSpeed > 0) {
                moveSpeed = it.moveSpeed
            }
            when (it.fishStatus) {
                FishStatus.EXCITING, FishStatus.FLESH_UP, FishStatus.BEAUTIFY -> {
                    if (visibility != View.VISIBLE) visibility = VISIBLE
                    postDelayed({
                        it.updateFishStatus(it.lastStatus)
                        notifyDataSetChanged()
                    }, it.recoverDelayMillis)
                    notifyDataSetChanged()

                }
                FishStatus.TRAVEL -> {
                    travel()
                }
                else -> {
                    if (visibility != View.VISIBLE) visibility = VISIBLE
                    notifyDataSetChanged()
                }
            }
        }
    }

    private fun notifyDataSetChanged() {
        when (trailType) {
            1 -> {
                when (currentDirection) {
                    Direction.MOVE_TO_LEFT -> {
                        moveLeft()
                    }
                    else -> {
                        moveRight()
                    }
                }
            }
            else -> {
                mPetAnimatorAdapter.notifyDataSetChanged()
            }
        }
    }


    /**
     * 弹出Tips操作.
     */
    fun tips() {
        mPetFish?.let {
            if (it.fishStatus != FishStatus.TRAVEL) {
                it.tips()?.let { tip ->
                    if (tvTips.visibility != View.VISIBLE) {
                        tvTips.text = tip
                        tvTips.visibility = View.VISIBLE
                        postDelayed({
                            tvTips.visibility = View.INVISIBLE
                        }, 6 * 1000L)
                    }
                }
            }
        }
    }

    fun setOnPetClickListener(l: OnClickListener?) {
        mOnPetClickListener = l
    }

    /**
     * callback on the per status.
     */
    private var onPetChangeListener: ((PetFish, PetView, PetAction) -> Unit)? = null

    fun petChangeListener(block: (PetFish, PetView, PetAction) -> Unit) {
        onPetChangeListener = block
    }

    private var mLastX = 0F
    private var mLastY = 0F

    private var lastTranslationX = 0F
    private var lastTranslationY = 0F
    private var downTime = 0L

    private var mPetMoveEndListener: (() -> Unit)? = null

    /**
     *  View的坐标系是相对于父控件而言的
     *  event.x:获得触摸点在当前 View 的 X 轴坐标
     *  event.y:获得触摸点在当前 View 的 Y 轴坐标
     */
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            //手指 初次接触到屏幕 时触发
            MotionEvent.ACTION_DOWN -> {
                if (!dragEnabled) {
                    tips()
                    mOnPetClickListener?.onClick(this)
                    return false
                }
                mLastX = event.x
                mLastY = event.y
                lastTranslationX = translationX
                lastTranslationY = translationY
                mPetAnimatorAdapter.pause()
                downTime = System.currentTimeMillis()
            }
            //手指 在屏幕上滑动 时触发，会多次触发
            MotionEvent.ACTION_MOVE -> {
                isDragging = true
                val dx = x + (event.x - mLastX)
                translationX = when {
                    dx <= dMinX -> dMinX
                    dx >= dMaxX -> dMaxX
                    else -> dx
                }
                val dy = y + (event.y - mLastY)
                translationY = when {
                    dy <= dMinY -> dMinY
                    dy >= dMaxY -> dMaxY
                    else -> dy
                }
                Log.i(TAG, "onTouchEvent: translationY:$translationY")
            }
            //手指 离开屏幕 时触发
            MotionEvent.ACTION_UP -> {

                if ((System.currentTimeMillis() - downTime) <= 300L) {
                    tips()
                    mOnPetClickListener?.onClick(this)
                    mPetAnimatorAdapter.resume()
                    isDragging = false
                    return false
                }

                isPressed = false

                val currentTX = translationX
                val currentTY = translationY
                translationX = lastTranslationX
                translationY = lastTranslationY

                //根据X位移差距判断左右朝向
                if ((currentTX - lastTranslationX) < 0) {
                    //从左向右
                    moveRight()
                } else {
                    //从右向左
                    moveLeft()
                }

                val backAnimatorX = ObjectAnimator.ofFloat(
                    this,
                    View.TRANSLATION_X,
                    currentTX,
                    lastTranslationX
                )
                val backAnimatorY =
                    ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, currentTY, lastTranslationY)

                val animatorSet = AnimatorSet()
                animatorSet.duration = 1000
                //animatorSet.interpolator = AccelerateInterpolator()
                //animatorSet.interpolator = DecelerateInterpolator()
                animatorSet.interpolator = LinearInterpolator()
                animatorSet.addListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationEnd(animation: Animator) {
                        mPetAnimatorAdapter.notifyDataSetChanged()
                        mPetAnimatorAdapter.resume()
                        isDragging = false
                    }
                })
                animatorSet.playTogether(backAnimatorX, backAnimatorY)
                animatorSet.start()
            }
            //事件 被上层拦截 时触发
            MotionEvent.ACTION_CANCEL -> {
                isPressed = false
                isDragging = false
                mPetAnimatorAdapter.resume()
            }
            //手指 不在控件区域 时触发
            MotionEvent.ACTION_OUTSIDE -> {
                isPressed = false
            }
        }
        return dragEnabled && !isDragging
    }

    private var isMoveInit = false

    private var dMinX = 0F
    private var dMinY = 0F
    private var dMaxX = 0F
    private var dMaxY = 0F

    private fun moveToStarting(parentWidth: Float, parentHeight: Float) {
        if (isMoveInit) return
        dMaxX = parentWidth - width
        dMaxY = parentHeight - height - dp2px(context, 85F)
        translationX = dMaxX
        translationY = dMaxY
        isMoveInit = true
    }

    var dragEnabled = false
    private var isDragging = false

    /**
     * 轨迹类型:0:固定,1:随机.默认随机.
     */
    var trailType = 1
//    var autoplay = false

    /**
     * 触摸移动进行中.
     */
//    private var isInTouching = false

    private val targetPointF = PointF()

    /**
     * 更新下一终点目标坐标点.
     */
    private fun updateTarget(
        targetX: Float = createRandom(targetRect.left, targetRect.right),
        targetY: Float = createRandom(targetRect.top, targetRect.bottom)
    ): PointF {
        targetPointF.x = targetX
        targetPointF.y = targetY
        return targetPointF
    }

    /**
     * 以先加速在减速的方式,将指定view移动至目标坐标处.
     *
     */
    private fun moveToTarget(isDelay: Boolean = true) {
        val startDelay = if (isDelay) 100L * 5 else 0L
        val targetX = targetPointF.x
        val targetY = targetPointF.y
        //val interpolator = if (isInTouching) AccelerateInterpolator() else null
        val interpolator = if (moveType == MOVE_TOUCH) AccelerateInterpolator() else null
        animate().translationX(targetX)
            .translationY(targetY)
            .setDuration(moveDuration())
            .setInterpolator(interpolator)
            .withLayer()
            .setListener(object : Animator.AnimatorListener {

                override fun onAnimationStart(animation: Animator) {
                    Log.i(TAG, "onAnimationStart: ")
                    when (currentDirection) {
                        Direction.MOVE_TO_LEFT -> moveLeft()
                        Direction.MOVE_TO_RIGHT -> moveRight()
                    }
                }

                override fun onAnimationEnd(animation: Animator) {
                    Log.i(TAG, "onAnimationEnd: $moveType")
                    when (moveType) {
                        MOVE_AUTO -> autoMove()
                        MOVE_TOUCH -> {
                            mPetMoveEndListener?.invoke()
                            autoMove()
                        }
                        MOVE_FEED -> eatFood()
                    }
                }

                override fun onAnimationCancel(animation: Animator) {

                }

                override fun onAnimationRepeat(animation: Animator) {

                }
            })
            .setStartDelay(startDelay)
            .start()
    }

    private fun eatFood() {
        for (v in foodList) {
            v.stopMove()
            v.visibility = View.GONE
        }
        onEatListener?.invoke()
        postDelayed({ autoMove() }, 1200)
    }

    private fun turnNext(nextDirection: Direction, usedImage: Boolean = true) {
        if (usedImage) {
            when (nextDirection) {
                Direction.MOVE_TO_LEFT -> turnLeft()
                Direction.MOVE_TO_RIGHT -> turnRight()
            }
            currentDirection = nextDirection
            moveToTarget()
        } else {
            val tempRotationY = when (nextDirection) {
                Direction.MOVE_TO_LEFT -> 360F
                Direction.MOVE_TO_RIGHT -> 180F
            }
            val turnDuration = 10L * 5
            animate()
                .rotationY(tempRotationY)
                //.setStartDelay(500)
                .setDuration(turnDuration)
                .setInterpolator(LinearInterpolator())
                .setListener(object : AnimatorListenerAdapter() {

                    override fun onAnimationEnd(animation: Animator) {
                        Log.i(TAG, "onAnimationEnd: ")
                        currentDirection = nextDirection
                        moveToTarget()
                    }
                }).start()
        }

    }

    /**
     * 下一个目的地的方向.
     * @param targetX 下一个目的地的targetX坐标.
     */
    private fun nextDirection(targetX: Float): Direction =
        if ((targetX - x) > 0) Direction.MOVE_TO_RIGHT else Direction.MOVE_TO_LEFT

    enum class Direction {
        MOVE_TO_LEFT, MOVE_TO_RIGHT
    }

    private var currentDirection = Direction.MOVE_TO_LEFT

    private fun touchMove(targetX: Float, targetY: Float) {
        moveType = MOVE_TOUCH
        updateTarget(targetX, targetY)
        val nextDirection = nextDirection(targetX)
        if (currentDirection != nextDirection) {
            turnNext(nextDirection)
        } else {
            moveToTarget(false)
        }
    }

    /**
     * 計算移動速度.
     */
    private fun moveDuration(): Long {
        movePath.reset()
        movePath.moveTo(x, y)
        movePath.lineTo(targetPointF.x, targetPointF.y)
        mPathMeasure.setPath(movePath, false)
        //val speed = if (isInTouching) moveSpeed * 2 else moveSpeed
        //val speed = if (moveType == MOVE_TOUCH) moveSpeed * 2 else moveSpeed
        val speed = when (moveType) {
            MOVE_FEED -> moveSpeed * 5
            MOVE_TOUCH -> moveSpeed * 2
            else -> moveSpeed
        }
        return (mPathMeasure.length.toLong() * SPEED_MOVE_SECOND / speed)
    }

    private val movePath = Path()

    /**
     * 取得min到max之间的随机整数（不包含max）
     * @min 最小取值
     * @max 最大取值边界（此值不取）
     * */
    private fun createRandom(min: Int = 0, max: Int): Float = when {
        abs(max - min) <= 100 -> Random.nextInt(min(min, max), max(min, max) + 100).toFloat()
        else -> Random.nextInt(min(min, max), max(min, max)).toFloat()
    }

    /**
     * 以触摸点做为目标点进行移动.Event
     */
    fun touchMoveByParent(event: MotionEvent): Boolean {
        Log.i(TAG, "touchMove: ")
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {

            }
            MotionEvent.ACTION_MOVE -> {

            }
            MotionEvent.ACTION_UP -> {
                //autoplay = false
                stopMove()
                //autoplay = true
                //isInTouching = true
                val touchX = event.x - petWidth / 2
                val touchY = event.y - petHeight / 2
                touchMove(touchX, touchY)
            }
            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_OUTSIDE, MotionEvent.ACTION_POINTER_DOWN -> {

            }
        }
        return true
    }

    fun petMoveEndListener(block: () -> Unit) {
        mPetMoveEndListener = block
    }

    /**
     * 寻找食物移动.
     */
    private fun feedMove(x: Float, y: Float) {
        //autoplay = false

        moveType = MOVE_FEED
        updateTarget(x, y)
        val targetX = targetPointF.x
        val nextDirection = nextDirection(targetX)
        if (currentDirection != nextDirection) {
            turnNext(nextDirection)
        } else {
            moveToTarget(false)
        }
    }

    /**
     * 移动类型:手指触摸移动(MOVE_TOUCH),自动随机移动(MOVE_AUTO),寻找食物移动(MOVE_FEED).
     */
    private var moveType = MOVE_STOP

    private fun stopMove() {
        moveType = MOVE_STOP
        animate().cancel()
    }

    private var onEatListener: (() -> Unit)? = null

    fun eatListener(block: () -> Unit) {
        onEatListener = block
    }

    fun feed(v: FoodView) {
        foodList.add(v)
        stopMove()
        feedMove(v.translationX, v.translationY)
    }

    /**
     * 喂食功能
     */
    fun feed(list: List<FoodView>) {
        //list.shuffled().take(1)[0]
        foodList.clear()
        if (list.size == 1) {
            foodList.addAll(list)
        } else {
            val count = Random.nextInt(1, list.size)
            foodList.addAll(list.shuffled().take(count))
        }
        stopMove()
        val v = foodList.last()
        feedMove(v.translationX, v.translationY)
    }

    private val foodList = mutableListOf<FoodView>()

}

//private var foodView: FoodView? = null
//    override fun onClick(v: View) {
//        when (v.id) {
//            R.id.ivFish -> {
//                tips()
//            }
//            else -> mOnPetClickListener?.onClick(v)
//        }
//    }